<template>
  <div class="live-container" :class="{ 'web-fullscreen': isWebFullscreen }">
    <div class="video-container">
      <video ref="videoElement" autoplay playsinline :muted="isMuted" @dblclick="toggleFullscreen"></video>

      <!-- 智能框渲染层 -->
      <div class="bounding-box-overlay" ref="boundingBoxOverlay" :style="overlayStyle">
        <div v-for="box in boundingBoxes" :key="`${box.frameId}-${box.classId}-${box.x}-${box.y}`" class="bounding-box"
          :data-class="box.label" :style="{
            left: (box.x * 100) + '%',
            top: (box.y * 100) + '%',
            width: (box.width * 100) + '%',
            height: (box.height * 100) + '%',
          }">
          <div class="box-border"></div>
          <div class="box-label">
            {{ box.label }} ({{ Math.round(box.confidence * 100) }}%)
          </div>
        </div>
      </div>

      <div class="control-overlay">
        <a-space>
          <a-button type="primary" ghost @click="toggleAudio" class="sound-button">
            <template #icon>
              <SoundOutlined />
              <div v-if="isMuted" class="mute-line"></div>
            </template>
          </a-button>
          <a-button type="primary" ghost @click="toggleBoundingBoxes" class="ai-button">
            <template #icon>
              <BulbOutlined :style="{ color: showBoundingBoxes ? '#1890ff' : '#fff' }" />
            </template>
          </a-button>
          <a-button type="primary" ghost @click="toggleWebFullscreen">
            <template #icon>
              <ExpandOutlined v-if="!isWebFullscreen" />
              <CompressOutlined v-else />
            </template>
          </a-button>
          <a-button type="primary" ghost @click="toggleFullscreen">
            <template #icon>
              <FullscreenOutlined />
            </template>
          </a-button>
        </a-space>
      </div>
    </div>
    <a-alert v-if="error" :message="error" type="error" showIcon banner />
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import {
  FullscreenOutlined,
  SoundOutlined,
  ExpandOutlined,
  CompressOutlined,
  BulbOutlined
} from '@ant-design/icons-vue'
import { JsonRpcClient } from '../../utils/jsonRpc.js'

const router = useRouter()
const route = useRoute()

const videoElement = ref(null)
const webrtcPeerConnection = ref(null)
const rpcClient = ref(null)
const websocket = ref(null)
const isConnected = ref(false)
const error = ref('')
const reconnectTimer = ref(null)
const isComponentMounted = ref(true)
const isMuted = ref(true)
const isWebFullscreen = ref(false)

// 智能框相关数据
const boundingBoxes = ref([])
const showBoundingBoxes = ref(true)
const boundingBoxOverlay = ref(null)
const videoRenderInfo = ref({
  width: 0,
  height: 0,
  offsetX: 0,
  offsetY: 0
})

const overlayStyle = computed(() => {
  return {
    display: showBoundingBoxes.value ? 'block' : 'none',
    width: `${videoRenderInfo.value.width}px`,
    height: `${videoRenderInfo.value.height}px`,
    left: `${videoRenderInfo.value.offsetX}px`,
    top: `${videoRenderInfo.value.offsetY}px`
  }
})

const configuration = {
  iceServers: [],  // 空数组禁用STUN/TURN
  iceTransportPolicy: "all",    // 允许所有候选类型（但实际只有主机候选）
  bundlePolicy: "max-bundle"    // 合并媒体流
}

const connectWebSocket = () => {
  const wsProtocol = 'ws:'
  const wsHost = window.location.host

  // 获取登录时存储的token
  const token = localStorage.getItem('access_token')
  if (!token) {
    error.value = '未登录或token已过期'
    router.push('/login')
    return
  }

  // 检查token是否过期
  const tokenExpires = localStorage.getItem('token_expires')
  if (tokenExpires && parseInt(tokenExpires) < Date.now()) {
    error.value = 'token已过期，请重新登录'
    router.push('/login')
    return
  }

  // 通过URL参数传递token
  const wsUrl = `${wsProtocol}//${wsHost}/v1/webrtc/live?token=${encodeURIComponent(token)}`

  try {
    // 创建 WebSocket 连接
    websocket.value = new WebSocket(wsUrl)

    // 创建 JsonRpcClient 实例并设置WebSocket
    rpcClient.value = new JsonRpcClient()
    rpcClient.value.setWebSocket(websocket.value)

    // 注册 WebRTC 相关的方法处理器
    rpcClient.value.registerMethod('webrtc.offer', handleOfferMethod)
    rpcClient.value.registerMethod('webrtc.iceCandidate', handleIceCandidateMethod)

    // 注册智能框数据处理器
    rpcClient.value.registerMethod('ai.boundingBoxes', handleBoundingBoxesMethod)

    // 监听 WebSocket 事件
    websocket.value.onopen = () => {
      console.log('[WebSocket] 连接已建立', new Date().toISOString())
      isConnected.value = true
      setupWebRTC()
    }

    websocket.value.onerror = (error) => {
      console.error('WebSocket error:', error)
      error.value = 'WebSocket连接错误，请检查网络或刷新页面重试'
    }

    websocket.value.onclose = (event) => {
      console.log('[WebSocket] 连接已断开', event.code, event.reason, new Date().toISOString())
      isConnected.value = false

      // 处理各种关闭原因
      if (event.code === 1008) {
        // 认证失败的情况才清除登录信息
        error.value = '认证失败，请重新登录'
        localStorage.clear();
        router.push('/login')
      } else if (event.code === 1006) {
        // 连接断开，但不清除登录信息，只显示错误提示
        error.value = '连接断开，可能是设备重启或网络问题，请刷新页面重试'
      } else {
        // 其他错误也不影响登录状态
        error.value = '连接断开，请刷新页面重试'
        // 只在组件仍然挂载时才设置重连定时器
        if (isComponentMounted.value) {
          reconnectTimer.value = setTimeout(connectWebSocket, 5000)
        }
      }
    }

    // 监听消息并使用 JsonRpcClient 处理
    websocket.value.onmessage = async (event) => {
      try {
        const message = JSON.parse(event.data)
        await rpcClient.value.handleMessage(message)
      } catch (err) {
        console.error('Failed to parse WebSocket message:', err)
      }
    }

  } catch (err) {
    console.error('Failed to create WebSocket connection:', err)
    error.value = 'WebSocket连接失败: ' + err.message + '，请检查网络连接或刷新页面重试'
  }
}

// 处理offer方法
const handleOfferMethod = async (params) => {
  if (!params.sdp || !params.type) {
    throw new Error('Invalid offer parameters')
  }

  console.log('Received WebRTC offer via RPC')
  await webrtcPeerConnection.value.setRemoteDescription(
    new RTCSessionDescription({
      type: params.type,
      sdp: params.sdp
    })
  )

  if (params.type === 'offer') {
    console.log('Creating answer...')
    const answer = await webrtcPeerConnection.value.createAnswer()
    console.log('Setting local description (answer)...')
    await webrtcPeerConnection.value.setLocalDescription(answer)

    // 通过RPC发送answer
    console.log('Sending answer via RPC...')
    try {
      await rpcClient.value.sendRequest('webrtc.answer', {
        type: 'answer',
        sdp: answer.sdp
      })
      console.log('Answer sent successfully')
    } catch (err) {
      console.error('Failed to send answer:', err)
    }
  }

  return { status: 'offer received' }
}

// 处理ICE候选方法
const handleIceCandidateMethod = async (params) => {
  if (!params.candidate) {
    throw new Error('Invalid ICE candidate parameters')
  }

  console.log('Adding ICE candidate via RPC...')
  await webrtcPeerConnection.value.addIceCandidate(
    new RTCIceCandidate({
      candidate: params.candidate,
      sdpMLineIndex: params.sdpMLineIndex
    })
  )

  return { status: 'ice candidate received' }
}

// 处理智能框数据方法
const handleBoundingBoxesMethod = async (params) => {
  if (params.boxes && Array.isArray(params.boxes)) {
    // 为每个框添加frameId用于key生成
    const boxesWithFrameId = params.boxes.map(box => ({
      ...box,
      frameId: params.frameId || Date.now()
    }))
    boundingBoxes.value = boxesWithFrameId
  }

  return { status: 'bounding boxes received' }
}

const toggleAudio = () => {
  isMuted.value = !isMuted.value
  if (videoElement.value) {
    videoElement.value.muted = isMuted.value
  }
}

const toggleWebFullscreen = () => {
  isWebFullscreen.value = !isWebFullscreen.value
}

// 切换智能框显示
const toggleBoundingBoxes = () => {
  showBoundingBoxes.value = !showBoundingBoxes.value
  // The overlay's display is now handled by computed overlayStyle
  // if (boundingBoxOverlay.value) {
  //   boundingBoxOverlay.value.style.display = showBoundingBoxes.value ? 'block' : 'none'
  // }
}

const updateOverlayPosition = () => {
  if (videoElement.value && boundingBoxOverlay.value && videoElement.value.videoWidth > 0 && videoElement.value.videoHeight > 0) {
    const video = videoElement.value
    const container = video.parentElement // video-container

    if (!container || container.clientWidth === 0 || container.clientHeight === 0) {
      // Wait for container to be ready
      requestAnimationFrame(updateOverlayPosition)
      return
    }

    const videoAspectRatio = video.videoWidth / video.videoHeight
    const containerAspectRatio = container.clientWidth / container.clientHeight

    let renderWidth, renderHeight, offsetX, offsetY

    if (videoAspectRatio > containerAspectRatio) {
      // Video is wider than container, so it's letterboxed (black bars top/bottom)
      renderWidth = container.clientWidth
      renderHeight = renderWidth / videoAspectRatio
      offsetX = 0
      offsetY = (container.clientHeight - renderHeight) / 2
    } else {
      // Video is taller than container, so it's pillarboxed (black bars left/right)
      renderHeight = container.clientHeight
      renderWidth = renderHeight * videoAspectRatio
      offsetY = 0
      offsetX = (container.clientWidth - renderWidth) / 2
    }

    videoRenderInfo.value = { width: renderWidth, height: renderHeight, offsetX, offsetY }
  }
}

const setupWebRTC = async () => {
  try {
    webrtcPeerConnection.value = new RTCPeerConnection(configuration)

    webrtcPeerConnection.value.ontrack = (event) => {
      if (videoElement.value && event.streams[0]) {
        videoElement.value.srcObject = event.streams[0]
        videoElement.value.play().catch(console.warn)
      }
    }

    webrtcPeerConnection.value.onicecandidate = ({ candidate }) => {
      if (candidate) {
        // 通过RPC通知发送ICE候选
        rpcClient.value.sendNotification('webrtc.iceCandidate', {
          candidate: candidate.candidate,
          sdpMLineIndex: candidate.sdpMLineIndex,
          sdpMid: candidate.sdpMid
        })
      }
    }

    // 添加视频转码器
    webrtcPeerConnection.value.addTransceiver('video', {
      direction: 'recvonly',
      streams: [new MediaStream()]
    })

    // 添加音频转码器
    webrtcPeerConnection.value.addTransceiver('audio', {
      direction: 'recvonly',
      streams: [new MediaStream()]
    })

    // 通知服务端客户端已准备好接收offer
    rpcClient.value.sendNotification('webrtc.ready', {
      timestamp: Date.now()
    })

  } catch (err) {
    console.error('Error in setupWebRTC:', err)
    error.value = `WebRTC设置失败: ${err.message}，请检查浏览器兼容性或刷新页面重试`
  }
}

const toggleFullscreen = async () => {
  try {
    if (!document.fullscreenElement) {
      await videoElement.value.requestFullscreen()
    } else {
      await document.exitFullscreen()
    }
  } catch (err) {
    error.value = '全屏切换失败: ' + err.message
  }
}

// 清理所有连接和定时器
const cleanup = () => {
  if (webrtcPeerConnection.value) {
    webrtcPeerConnection.value.close()
    webrtcPeerConnection.value = null
  }

  if (rpcClient.value) {
    rpcClient.value.cleanup()
    rpcClient.value = null
  }

  if (websocket.value) {
    websocket.value.close()
    websocket.value = null
  }

  if (reconnectTimer.value) {
    clearTimeout(reconnectTimer.value)
    reconnectTimer.value = null
  }

  isConnected.value = false
}

// 使用组件内的路由监听
const unwatch = router.beforeEach((to, from, next) => {
  if (from.path.includes('/live')) {
    cleanup()
  }
  next()
})

onMounted(() => {
  isComponentMounted.value = true
  connectWebSocket()

  if (videoElement.value) {
    videoElement.value.onplaying = () => {
      updateOverlayPosition()
    }
  }
  window.addEventListener('resize', updateOverlayPosition)
  watch(isWebFullscreen, () => {
    // 等待CSS transition完成后再更新位置
    setTimeout(updateOverlayPosition, 350)
  })
  // Initial call in case video is already playing or for layout changes
  requestAnimationFrame(updateOverlayPosition)
})

onUnmounted(() => {
  isComponentMounted.value = false
  cleanup()
  unwatch()
  window.removeEventListener('resize', updateOverlayPosition)
  if (videoElement.value) {
    videoElement.value.onplaying = null
  }
})
</script>

<style scoped>
.live-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: transparent;
  padding: 16px;
  box-sizing: border-box;
  overflow: hidden;
  transition: all 0.3s ease;
}

/* 网页全屏模式的样式 */
.web-fullscreen {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
  padding: 0;
  background-color: #000;
}

.video-container {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  background-color: #000;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

video {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

.web-fullscreen video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.control-overlay {
  position: absolute;
  top: 16px;
  right: 16px;
  opacity: 0;
  transition: opacity 0.3s ease;
  z-index: 10;
}

.video-container:hover .control-overlay {
  opacity: 1;
}

:deep(.ant-alert-banner) {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  margin: 0;
  z-index: 10;
}

.mute-icon {
  position: relative;
  color: #ff4d4f;
}

:deep(.mute-icon .anticon-close-circle) {
  font-size: 16px;
  position: absolute;
  bottom: -2px;
  right: -2px;
}

/* 使用更贴近音量控制的图标 */
:deep(.ant-btn) {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(0, 0, 0, 0.5);
  border-color: rgba(255, 255, 255, 0.5);
  color: #fff;
  width: 40px;
  height: 40px;
  padding: 0;
  position: relative;
}

:deep(.ant-btn:hover) {
  background-color: rgba(0, 0, 0, 0.7);
  border-color: rgba(255, 255, 255, 0.7);
  color: #fff;
}

:deep(.anticon) {
  margin: 0;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sound-button {
  position: relative;
}

.mute-line {
  position: absolute;
  width: 100%;
  height: 2px;
  background-color: #ff4d4f;
  top: 50%;
  left: 0;
  transform: rotate(-45deg);
}
/* 智能框样式 */
.bounding-box-overlay {
  position: absolute;
  /* top: 0; */ /* Handled by JS */
  /* left: 0; */ /* Handled by JS */
  /* width: 100%; */ /* Handled by JS */
  /* height: 100%; */ /* Handled by JS */
  pointer-events: none;
  z-index: 5;
  transform-origin: top left; /* Ensures scaling is from top-left if needed */
}

.bounding-box {
  position: absolute;
  pointer-events: none;
}

.box-border {
  width: 100%;
  height: 100%;
  border: 2px solid #00ff00;
  box-shadow: 0 0 4px rgba(0, 255, 0, 0.6);
}

.box-label {
  position: absolute;
  top: -25px;
  left: 0;
  background-color: rgba(0, 255, 0, 0.8);
  color: #000;
  padding: 2px 6px;
  font-size: 12px;
  font-weight: bold;
  border-radius: 3px;
  white-space: nowrap;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 当标签超出视频顶部时，显示在框的下方 */
.bounding-box:hover .box-label {
  z-index: 10;
}

/* 针对不同类别的框使用不同颜色 */
.bounding-box[data-class="person"] .box-border {
  border-color: #00ff00;
  box-shadow: 0 0 4px rgba(0, 255, 0, 0.6);
}

.bounding-box[data-class="person"] .box-label {
  background-color: rgba(0, 255, 0, 0.8);
}

.bounding-box[data-class="car"] .box-border {
  border-color: #ff0000;
  box-shadow: 0 0 4px rgba(255, 0, 0, 0.6);
}

.bounding-box[data-class="car"] .box-label {
  background-color: rgba(255, 0, 0, 0.8);
  color: #fff;
}

.bounding-box[data-class="bicycle"] .box-border {
  border-color: #0000ff;
  box-shadow: 0 0 4px rgba(0, 0, 255, 0.6);
}

.bounding-box[data-class="bicycle"] .box-label {
  background-color: rgba(0, 0, 255, 0.8);
  color: #fff;
}
</style>
